/**
 * Hook for managing real-time sequential content updates from the main process.
 *
 * This hook manages the complex state synchronization between the main process
 * MCP reflection->action workflow and the renderer's UI display. It handles:
 *
 * - Initial content parsing from stored database state
 * - Real-time event listeners for live content streaming
 * - Block creation, updates, and completion notifications
 * - Proper cleanup to prevent memory leaks
 *
 * The hook coordinates multiple IPC event types to provide a seamless
 * streaming experience for the MCP workflow.
 */

import logger from "@shared/logger/renderer-logger";
import type { ToolCallResult } from "@shared/types/openai";
import type {
  ContentBlock,
  SequentialMessageContent,
} from "@shared/types/sequential-content";
import { useCallback, useEffect, useState } from "react";

const { ipcRenderer } = window.electron;

/**
 * @param messageId - Database ID of the message to track
 * @param contentBlocks - JSON string of initial SequentialMessageContent from database
 * @param hasSequentialContent - Whether this message uses the new sequential format
 * @returns Object with current blocks, sequential status, and loading state
 */
export function useSequentialContentUpdates(
  messageId: string,
  contentBlocks?: string,
  hasSequentialContent?: boolean,
): {
  blocks: ContentBlock[];
  isSequential: boolean;
  isLoading: boolean;
} {
  const [blocks, setBlocks] = useState<ContentBlock[]>([]);
  const [isLoading, setIsLoading] = useState(false);

  // Parse initial content blocks from database on first load
  useEffect(() => {
    if (!hasSequentialContent || !contentBlocks) {
      setBlocks([]);
      setIsLoading(false);
      return;
    }

    try {
      setIsLoading(true);
      const sequentialContent: SequentialMessageContent =
        JSON.parse(contentBlocks);
      setBlocks(sequentialContent.blocks || []);
    } catch (error) {
      logger.error("Failed to parse sequential content blocks", {
        error,
        contentBlocks,
      });
      setBlocks([]);
    } finally {
      setIsLoading(false);
    }
  }, [contentBlocks, hasSequentialContent]);

  /**
   * Handles the addition of new content blocks from the main process.
   *
   * This event fires when:
   * - A new reflection block is created for AI thinking
   * - A new tool call block is added for function execution
   *
   * The handler ensures blocks are properly ordered and handles both
   * new block creation and updates to existing blocks.
   */
  const handleContentBlockAdd = useCallback(
    (
      _event: Electron.IpcRendererEvent,
      data: {
        threadId: string;
        messageId: string;
        blockId: string;
        blockType?: "reflection" | "tool_call";
        order?: number;
        block?: ContentBlock;
      },
    ) => {
      logger.debug("Received CONTENT_BLOCK_ADD event", {
        receivedMessageId: data.messageId,
        currentMessageId: messageId,
        blockId: data.blockId,
        hasBlock: !!data.block,
        blockType: data.block?.type,
      });

      // Ensure we have the correct message and required data
      if (data.messageId === messageId && data.block) {
        const block = data.block; // Extract to const for type narrowing
        setBlocks((prevBlocks) => {
          const existingIndex = prevBlocks.findIndex(
            (existingBlock) => existingBlock.id === block.id,
          );
          if (existingIndex >= 0) {
            // Block already exists - update it with new data
            const updatedBlocks = [...prevBlocks];
            updatedBlocks[existingIndex] = block;
            logger.debug("Updated existing block", { blockId: block.id });
            return updatedBlocks;
          } else {
            // New block - add it and maintain chronological order
            const newBlocks = [...prevBlocks, block].sort(
              (a, b) => a.order - b.order,
            );
            logger.debug("Added new block", {
              blockId: block.id,
              totalBlocks: newBlocks.length,
            });
            return newBlocks;
          }
        });
      }
    },
    [messageId],
  );

  /**
   * Handles updates to existing content blocks.
   *
   * This event fires for partial updates to blocks, such as:
   * - Updating reflection content during streaming
   * - Changing tool call status (pending -> success/error)
   * - Modifying execution state flags
   *
   * The handler performs type-safe updates based on block type.
   */
  const handleContentBlockUpdate = useCallback(
    (
      _event: Electron.IpcRendererEvent,
      data: {
        threadId: string;
        messageId: string;
        blockId: string;
        updateData: {
          content?: string;
          isComplete?: boolean;
          toolCall?: ToolCallResult;
          isExecuting?: boolean;
          // NEW: allow full replacement of blocks to support truncation before rerun
          replaceBlocks?: ContentBlock[];
        };
      },
    ) => {
      logger.debug("Received CONTENT_BLOCK_UPDATE event", {
        receivedMessageId: data.messageId,
        currentMessageId: messageId,
        blockId: data.blockId,
        hasUpdateData: !!data.updateData,
        updateDataKeys: data.updateData ? Object.keys(data.updateData) : [],
      });

      if (data.messageId === messageId) {
        // If replaceBlocks is provided, replace the entire blocks list immediately
        const replacePayload = data.updateData as {
          replaceBlocks?: ContentBlock[];
        };
        if (replacePayload && Array.isArray(replacePayload.replaceBlocks)) {
          const nextBlocks = replacePayload.replaceBlocks as ContentBlock[];
          setBlocks(
            [...nextBlocks].sort((a, b) => (a.order || 0) - (b.order || 0)),
          );
          return;
        }

        setBlocks((prevBlocks) => {
          const blockIndex = prevBlocks.findIndex(
            (block) => block.id === data.blockId,
          );
          if (blockIndex >= 0) {
            const updatedBlocks = [...prevBlocks];
            const existingBlock = updatedBlocks[blockIndex];

            // Type-safe updates based on block type and available data
            if (
              existingBlock.type === "reflection" &&
              data.updateData?.content !== undefined
            ) {
              // Update reflection content (typically during streaming)
              updatedBlocks[blockIndex] = {
                ...existingBlock,
                content: data.updateData.content,
                isComplete:
                  data.updateData.isComplete ?? existingBlock.isComplete,
              };
              logger.debug("Updated reflection block", {
                blockId: data.blockId,
                contentLength: data.updateData.content?.length || 0,
                isComplete: data.updateData.isComplete,
              });
            } else if (
              existingBlock.type === "tool_call" &&
              data.updateData?.toolCall
            ) {
              // Update tool call status and execution state
              updatedBlocks[blockIndex] = {
                ...existingBlock,
                toolCall: data.updateData.toolCall,
                isExecuting:
                  data.updateData.isExecuting ?? existingBlock.isExecuting,
              };
              logger.debug("Updated tool call block", {
                blockId: data.blockId,
                toolName: data.updateData.toolCall.name,
                status: data.updateData.toolCall.status,
                isExecuting: data.updateData.isExecuting,
              });
            }

            return updatedBlocks;
          } else {
            logger.warn("Block not found for update", {
              blockId: data.blockId,
              availableBlocks: prevBlocks.map((b) => ({
                id: b.id,
                type: b.type,
              })),
            });
          }
          return prevBlocks;
        });
      }
    },
    [messageId],
  );

  const handleReflectionContent = useCallback(
    (
      _event: Electron.IpcRendererEvent,
      data: {
        threadId: string;
        messageId: string;
        blockId: string;
        content: string;
        isComplete: boolean;
      },
    ) => {
      logger.debug("Received MCP_REFLECTION_CONTENT event", {
        receivedMessageId: data.messageId,
        currentMessageId: messageId,
        blockId: data.blockId,
        contentLength: data.content?.length || 0,
        isComplete: data.isComplete,
      });

      if (data.messageId === messageId) {
        setBlocks((prevBlocks) => {
          const blockIndex = prevBlocks.findIndex(
            (block) => block.id === data.blockId,
          );
          if (blockIndex >= 0) {
            const updatedBlocks = [...prevBlocks];
            const existingBlock = updatedBlocks[blockIndex];

            if (existingBlock.type === "reflection") {
              updatedBlocks[blockIndex] = {
                ...existingBlock,
                content: data.content,
                isComplete: data.isComplete ?? false,
              };
            }

            return updatedBlocks;
          } else {
            logger.warn("Block not found for reflection content update", {
              blockId: data.blockId,
              availableBlocks: prevBlocks.map((b) => ({
                id: b.id,
                type: b.type,
              })),
            });
          }
          return prevBlocks;
        });
      }
    },
    [messageId],
  );

  const handleSequentialContentComplete = useCallback(
    (
      _event: Electron.IpcRendererEvent,
      data: {
        threadId: string;
        messageId: string;
        totalBlocks: number;
      },
    ) => {
      if (data.messageId === messageId) {
        // Mark all blocks as complete
        setBlocks((prevBlocks) =>
          prevBlocks.map((block) => {
            if (block.type === "reflection") {
              return { ...block, isComplete: true };
            } else if (block.type === "tool_call") {
              return { ...block, isExecuting: false };
            }
            return block;
          }),
        );
        setIsLoading(false);
      }
    },
    [messageId],
  );

  /**
   * Handle tool call approval required events
   * Updates the tool call status to awaiting_approval when approval is needed
   */
  const handleToolCallApprovalRequired = useCallback(
    (
      _event: Electron.IpcRendererEvent,
      data: {
        threadId: string;
        messageId: string;
        toolCallId: string;
        toolName: string;
        toolArguments: string;
        mcpServerId: string;
      },
    ) => {
      logger.debug("Received TOOL_CALL_APPROVAL_REQUIRED event", {
        receivedMessageId: data.messageId,
        currentMessageId: messageId,
        toolCallId: data.toolCallId,
        toolName: data.toolName,
      });

      if (data.messageId === messageId) {
        setBlocks((prevBlocks) => {
          const updatedBlocks = [...prevBlocks];
          let updated = false;

          for (let i = 0; i < updatedBlocks.length; i++) {
            const block = updatedBlocks[i];
            if (
              block.type === "tool_call" &&
              block.toolCall.id === data.toolCallId
            ) {
              updatedBlocks[i] = {
                ...block,
                toolCall: {
                  ...block.toolCall,
                  status: "awaiting_approval" as const,
                  requiresApproval: true,
                },
                isExecuting: true, // Keep showing as executing
              };
              updated = true;
              logger.debug("Updated tool call block to awaiting_approval", {
                blockId: block.id,
                toolCallId: data.toolCallId,
                toolName: data.toolName,
              });
              break;
            }
          }

          if (!updated) {
            logger.warn("Tool call block not found for approval update", {
              toolCallId: data.toolCallId,
              availableBlocks: prevBlocks
                .filter((b) => b.type === "tool_call")
                .map((b) => ({
                  id: b.id,
                  toolCallId: b.type === "tool_call" ? b.toolCall.id : null,
                })),
            });
          }

          return updatedBlocks;
        });
      }
    },
    [messageId],
  );

  // Set up real-time event listeners
  useEffect(() => {
    if (!hasSequentialContent || !messageId) {
      return;
    }

    logger.debug("Setting up sequential content event listeners", {
      messageId,
      hasSequentialContent,
    });

    // Add event listeners using the correct event names from EventNames
    ipcRenderer.on("content-block:add", handleContentBlockAdd);
    ipcRenderer.on("content-block:update", handleContentBlockUpdate);
    ipcRenderer.on("mcp-reflection:content", handleReflectionContent);
    ipcRenderer.on(
      "sequential-content:complete",
      handleSequentialContentComplete,
    );
    ipcRenderer.on(
      "tool-call:approval-required",
      handleToolCallApprovalRequired,
    );

    // Cleanup event listeners - remove only the specific listeners we added
    return () => {
      logger.debug("Cleaning up sequential content event listeners", {
        messageId,
      });
      ipcRenderer.removeListener("content-block:add", handleContentBlockAdd);
      ipcRenderer.removeListener(
        "content-block:update",
        handleContentBlockUpdate,
      );
      ipcRenderer.removeListener(
        "mcp-reflection:content",
        handleReflectionContent,
      );
      ipcRenderer.removeListener(
        "sequential-content:complete",
        handleSequentialContentComplete,
      );
      ipcRenderer.removeListener(
        "tool-call:approval-required",
        handleToolCallApprovalRequired,
      );
    };
  }, [
    hasSequentialContent,
    messageId,
    handleContentBlockAdd,
    handleContentBlockUpdate,
    handleReflectionContent,
    handleSequentialContentComplete,
    handleToolCallApprovalRequired,
  ]);

  return {
    blocks,
    isSequential: hasSequentialContent || false,
    isLoading,
  };
}
